package com.jwater.core.serialize;

import com.jwater.core.common.S;
import com.jwater.core.net.NetException;

import jwater.org.apache.mina.core.buffer.IoBuffer;

/**
 * @description:
 * @author: jnner
 * @createDate: 2021/2/5
 * @version: 1.0
 */
public class SimpleSerialize extends AbstractSerialize {
    public static final Short TYPE_INTEGER = 1;
    public static final Short TYPE_SHORT = 2;
    public static final Short TYPE_LONG = 3;
    public static final Short TYPE_STRING = 4;
    public static final Short TYPE_DOUBLE = 5;
    public static final Short TYPE_FLOAT = 6;
    public static final Short TYPE_BOOLEAN = 7;
    public static final Short TYPE_BYTE_ARRAY = 8;

    public static final Short TYPE_VALUE_NOT_EMPTY = 0;
    public static final Short TYPE_VALUE_EMPTY = 1;

    public static boolean isSimpleType(Object obj) {
        if (obj instanceof Integer) {
        } else if (obj instanceof Short) {
        } else if (obj instanceof Long) {
        } else if (obj instanceof String) {
        } else if (obj instanceof Double) {
        } else if (obj instanceof Float) {
        } else if (obj instanceof Boolean) {
        } else {
            return false;
        }
        return true;
    }

    /**
     * 序列化
     *
     * @param obj
     * @param <T>
     * @return
     * @throws SerializeException
     */
    @Override
    public <T> byte[] serialize(T obj) throws SerializeException {
        try {
            if (obj == null) {
                IoBuffer buffer = IoBuffer.allocate(2);
                buffer.putShort(TYPE_VALUE_EMPTY);
                return buffer.array();
            } else {
                IoBuffer buffer = null;
                if (obj instanceof Integer) {
                    buffer = IoBuffer.allocate(8);
                    buffer.putShort(TYPE_VALUE_NOT_EMPTY);
                    buffer.putShort(TYPE_INTEGER);
                    buffer.putInt((Integer) obj);
                } else if (obj instanceof Short) {
                    buffer = IoBuffer.allocate(6);
                    buffer.putShort(TYPE_VALUE_NOT_EMPTY);
                    buffer.putShort(TYPE_SHORT);
                    buffer.putShort((Short) obj);
                } else if (obj instanceof Long) {
                    buffer = IoBuffer.allocate(12);
                    buffer.putShort(TYPE_VALUE_NOT_EMPTY);
                    buffer.putShort(TYPE_LONG);
                    buffer.putLong((Long) obj);
                } else if (obj instanceof String) {
                    byte[] data = obj.toString().getBytes(S.charset);
                    buffer = IoBuffer.allocate(4 + data.length);
                    buffer.putShort(TYPE_VALUE_NOT_EMPTY);
                    buffer.putShort(TYPE_STRING);
                    buffer.put(data);
                } else if (obj instanceof Double) {
                    buffer = IoBuffer.allocate(12);
                    buffer.putShort(TYPE_VALUE_NOT_EMPTY);
                    buffer.putShort(TYPE_DOUBLE);
                    buffer.putDouble((Double) obj);
                } else if (obj instanceof Float) {
                    buffer = IoBuffer.allocate(8);
                    buffer.putShort(TYPE_VALUE_NOT_EMPTY);
                    buffer.putShort(TYPE_FLOAT);
                    buffer.putFloat((Float) obj);
                } else if (obj instanceof Boolean) {
                    buffer = IoBuffer.allocate(6);
                    buffer.putShort(TYPE_VALUE_NOT_EMPTY);
                    buffer.putShort(TYPE_BOOLEAN);
                    Boolean value = (Boolean) obj;
                    buffer.putShort((short) (value ? 1 : 0));
                } else if (obj instanceof byte[]) {
                    byte[] data = (byte[]) obj;
                    buffer = IoBuffer.allocate(4 + data.length);
                    buffer.putShort(TYPE_VALUE_NOT_EMPTY);
                    buffer.putShort(TYPE_BYTE_ARRAY);
                    buffer.put(data);
                } else {
                    throw new SerializeException("not support serialize type for " + obj.getClass().getName());
                }
                return buffer.array();
            }
        } catch (Exception e) {
            throw new SerializeException("SimpleSerialize Serialize error", e);
        }
    }

    /**
     * 基本类型反序列化
     *
     * @param data
     * @param clazz
     * @param <T>
     * @return
     * @throws SerializeException
     */
    @SuppressWarnings("unchecked")
    @Override
    public <T> T deserialize(byte[] data, Class<T> clazz) throws SerializeException {
        try {
            IoBuffer buffer = IoBuffer.wrap(data);
            short emptyValue = buffer.getShort();
            if (emptyValue == TYPE_VALUE_EMPTY) {
                return null;
            } else {
                Object value;
                short type = buffer.getShort();
                if (type == TYPE_INTEGER) {
                    value = buffer.getInt();
                } else if (type == TYPE_SHORT) {
                    value = buffer.getShort();
                } else if (type == TYPE_LONG) {
                    value = buffer.getLong();
                } else if (type == TYPE_STRING) {
                    byte[] bytes = new byte[data.length - 4];
                    buffer.get(bytes);
                    value = new String(bytes, 0, bytes.length, S.charset);
                } else if (type == TYPE_DOUBLE) {
                    value = buffer.getDouble();
                } else if (type == TYPE_FLOAT) {
                    value = buffer.getFloat();
                } else if (type == TYPE_BOOLEAN) {
                    value = buffer.getShort() == 1;
                } else if (type == TYPE_BYTE_ARRAY) {
                    byte[] bytes = new byte[data.length - 4];
                    buffer.get(bytes);
                    value = bytes;
                } else {
                    throw new NetException("not support deserialize type for " + type);
                }
                return (T) value;
            }
        } catch (Exception e) {
            throw new SerializeException("SimpleSerialize Deserialize error", e);
        }
    }
}
